using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using DNNToolkit.Modules.Resource;

namespace DNNToolkit.Modules.CityTaxLocator.Components
{
    public class StateBlockManager:IDisposable
    {
        private class StateBlock
        {
            #region constructors
            public StateBlock(
                long startLineOfStateBlock,
                long endLineOfStateBlock,
                string stateName
                )
            {
                mStartLineOfStateBlock = startLineOfStateBlock;
                mEndLineOfStateBlock = endLineOfStateBlock;
                mStateName = stateName;
                mStartLineNumOfCityRow = mStartLineOfStateBlock + 6;
                mEndLineNumOCityRowfRow = mEndLineOfStateBlock;
            }
            #endregion

            #region member varibles
            private readonly long mEndLineOfStateBlock;
            private readonly long mStartLineOfStateBlock;
            private readonly long mStartLineNumOfCityRow;
            private readonly long mEndLineNumOCityRowfRow;
            private readonly string mStateName;
            #endregion

            #region instance properties
            public long StartLineNumOfCityRow
            {
                get { return mStartLineNumOfCityRow; }
            }

            public long EndLineNumOfCityRow
            {
                get { return mEndLineNumOCityRowfRow; }
            }

            public string StateName
            {
                get { return mStateName; }
            }

            #endregion
        }

        #region constructors
        public StateBlockManager(FileStream fs)
        {
            fs.Position = 0;//reset the start position
            mDataFile = new StreamReader(fs);
        }
        #endregion

        #region instance varibles
        private readonly StreamReader mDataFile;
        private long mLineNum;
        #endregion

        #region instance interface methods
        

        public IEnumerable<StateItem> States()
        {            
            List<StateBlock> stateList = StateList;            

            foreach (StateBlock blockItem in stateList)
            {
                StringBuilder sb = new StringBuilder();

                sb.AppendLine(ReadToLine(blockItem.StartLineNumOfCityRow));
                while (mLineNum < blockItem.EndLineNumOfCityRow)
                {
                    sb.AppendLine(ReadLine());
                }

                yield return new StateItem(sb.ToString(), (blockItem.EndLineNumOfCityRow - blockItem.StartLineNumOfCityRow + 1)/3, blockItem.StateName);
            }
        }
        
        #endregion

        #region instance private methods
        private List<StateBlock> StateList
        {
            get
            {
                List<StateBlock> stateList = new List<StateBlock>();

                string readLine = ReadToLine(2);
                string preStateName;
                string nextStateName;
                if (IsStartPosition(readLine, out preStateName))
                {
                    while (true)
                    {
                        bool isFileEnd;
                        long startLineNumOfStateBlock = mLineNum - 1;
                        long endLineOfStateBlock = GetLastLineNumOfState(out isFileEnd, out nextStateName);

                        stateList.Add(
                                new StateBlock(
                                startLineNumOfStateBlock,
                                endLineOfStateBlock,
                                preStateName));

                        preStateName = nextStateName;
                        

                        if (isFileEnd)
                            break;

                    }
                }
                else
                {
                    throw new FileFormatException();
                }

                mDataFile.BaseStream.Position = 0;//reset the position
                mLineNum = 0;//reset the position
                return stateList;
            }
        }

        private bool IsStartPosition(string line,out string stateName)
        {
            if (line.IndexOf(Strings.StartTag) != -1)
            {                
                stateName = line.Substring(line.IndexOf(":") + 1, 40);
                stateName = stateName.TrimStart(" ".ToCharArray());
                stateName = stateName.TrimEnd(" ".ToCharArray());
                return true;
            }
            else
            {
                stateName = null;
                return false;
            }
        }


        private string ReadLine()
        {
            string strLine = mDataFile.ReadLine();
            if (strLine != null)
                mLineNum++;
            return strLine;
        }

        
        private string ReadToLine(long lineNum)
        {
            if (lineNum < mLineNum)
                throw new ArgumentException(Strings.StateBlockManager_InvalidLineNum);

            long n =lineNum - mLineNum ;

            if (n == 0)
                return null;

            string lineValue = null;
            for (int i = 0; i < n; i++)
            {
                lineValue = ReadLine();
                if (lineValue == null)
                    return null;
            }

            return lineValue;
        }

        private long GetLastLineNumOfState(out bool IsFileEnd, out string  stateName)
        {
            string lineValue = ReadLine();
            

            while (!IsStartPosition(lineValue, out stateName))
            {
                lineValue = ReadLine();
                if (lineValue == null)
                {
                    IsFileEnd = true;
                    return mLineNum;
                }
            }

            IsFileEnd = false;
            return mLineNum - 2;
        }
        #endregion

        #region IDisposable Members

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose managed resources
                mDataFile.Close();
            }
            // free native resources
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
